package dcc.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileFilter;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;

import dcc.mbg.model.BaseInfo;
import dcc.resources.code.EncryptDecrypt;
import dcc.tools.BeanFactory;
import dcc.tools.Tools;

public class DataExportService {

	private Logger logger = Logger.getLogger(this.getClass());

	public String exportData(List<BaseInfo> talents) throws Exception {
		File path = selectExportDirectory();
		if (path != null) {
			try {
				return export(talents, path);
			} catch (Exception e) {
				throw e;
			}
		}
		return null;
	}

	private void writeDataToFile(List<BaseInfo> talents, File path)
			throws Exception {
		File dataFile = null;
		FileOutputStream fos = null;
		OutputStreamWriter osw = null;
		try {
			dataFile = new File(path.getPath() + "\\"
					+ Tools.get().getValue("EXPORTDATAFILENAME"));
			if (!dataFile.exists()) {
				dataFile = new File(path.getPath() + "\\"
						+ Tools.get().getValue("EXPORTDATAFILENAME"));
				dataFile.createNewFile();
			}
			fos = new FileOutputStream(dataFile);
			osw = new OutputStreamWriter(fos, "utf-8");
			for (BaseInfo baseInfo : talents) {
				// TODO get common info fields string
				String baseInfoFieldsString = createFieldsString("EXPORTFORMAT_BaseInfo_Fields");
				logger.info("baseInfoFieldsString: " + baseInfoFieldsString);
				// get common info values string
				String baseInfoValuesString = createValuesString(
						"EXPORTFORMAT_BaseInfo_Values", baseInfo);
				logger.info("baseInfoValuesString: " + baseInfoValuesString);
				// TODO get other info fields string
				String otherInfoFieldsString = createFieldsString("EXPORTFORMAT_"
						+ Tools.get().getTalentTypeSymbol(baseInfo.getShiBieHao())
						+ "_Fields");
				logger.info("otherInfoFieldsString: " + otherInfoFieldsString);
				// get other info values string
				String typeSymbol = Tools.get().getTalentTypeSymbol(
						baseInfo.getShiBieHao());
				logger.info(typeSymbol);
				String otherInfoValuesString = createValuesString(
						"EXPORTFORMAT_" + typeSymbol + "_Values",
						getModel(typeSymbol, baseInfo.getId()));
				logger.info("otherInfoValuesString: " + otherInfoValuesString);

				StringBuffer insertSQL = new StringBuffer("insert into ");
				insertSQL.append(Tools.get().getValue(
						"EXPORTFORMAT_" + typeSymbol + "_Table"));
				insertSQL.append("(");
				insertSQL.append(baseInfoFieldsString);
				insertSQL.append(",");
				insertSQL.append(otherInfoFieldsString);
				insertSQL.append(") values(");
				insertSQL.append(baseInfoValuesString);
				insertSQL.append(",");
				insertSQL.append(otherInfoValuesString);
				insertSQL.append(");");
				logger.info(insertSQL.toString());
				osw.write(insertSQL.toString() + "\r\n");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (osw != null) {
				osw.close();
			}
			if (fos != null) {
				fos.close();
			}
		}
	}

	private Object getModel(String typeSymbol, int id) {
		try {
			String serviceName = typeSymbol.substring(0, 1).toLowerCase()
					+ typeSymbol.substring(1) + "Service";
			Object serviceBean = BeanFactory.getBean(serviceName);
			Method[] methods = serviceBean.getClass().getMethods();
			for (Method method : methods) {
				if (method.getName()
						.equals("get" + typeSymbol + "InfoByBaseId")) {
					return method.invoke(serviceBean, id);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	private String createFieldsString(String key) {
		String fieldsString = Tools.get().getValue(key);
		return fieldsString;
	}

	private String createValuesString(String key, Object model) {
		String valuesFormat = Tools.get().getValue(key);
		return replacePlaceholder(valuesFormat, model);
	}

	private String replacePlaceholder(String formatString, Object model) {
		StringBuffer stringBuffer = null;
		try {
			Field[] fields = model.getClass().getDeclaredFields();
			for (Field field : fields) {
				if (field.getName().equals("id")
						|| field.getName().equals("baseId")) {
					continue;
				} else {
					stringBuffer = new StringBuffer();
					stringBuffer.append("#{");
					stringBuffer.append(field.getName());
					stringBuffer.append("}");
					Method getMethod = model.getClass().getDeclaredMethod(
							"get" + field.getName());
					if (null != getMethod.invoke(model)) {
						String value = "\'"
								+ getMethod.invoke(model).toString()
										.replace("\'", "\'\'") + "\'";
						formatString = formatString.replace(
								stringBuffer.toString(), value);
					} else {
						formatString = formatString.replace(
								stringBuffer.toString(), "\'\'");
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return formatString;
	}

	private void copyPicsToDir(List<BaseInfo> talents, File path) {
		logger.info("pics path:" + path.getPath());
		for (BaseInfo baseInfo : talents) {
			try {
				if (!baseInfo.getZhaoPian().equals("")
						&& baseInfo.getZhaoPian() != null) {
					File srcPhoto = new File(System.getProperty("user.dir")
							+ "\\photos\\" + baseInfo.getZhaoPian());
					if (srcPhoto.exists()) {
						File desPhoto = new File(path.getPath() + "\\"
								+ Tools.get().getValue("EXPORTPICSFILENAME"));
						// FileUtils.copyFileToDirectory(srcPhoto, desPhoto);
						String webTableName = Tools.get().getValue(
								"EXPORTFORMAT_"
										+ Tools.get().getTalentTypeSymbol(
												baseInfo.getShiBieHao())
										+ "_Table");
						File desPhotoFile = new File(desPhoto.getPath() + "\\"
								+ webTableName + "-" + baseInfo.getZhaoPian());
						FileUtils.copyFile(srcPhoto, desPhotoFile);
					} else {
						continue;
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	private String export(List<BaseInfo> talents, File path) throws Exception {
		// TODO Export Data
		writeDataToFile(talents, path);
		copyPicsToDir(talents, path);
		// TODO Zip
		try {
			return zip(path);
		} catch (Exception e) {
			// TODO delete pdb file;
			deleteTempZipFile(path.getPath() + ".pdb");
			// TODO throw Exception;
			throw e;
		} finally {
			// TODO delete temp directory File;
			deleteTempFile(path);
		}
	}

	private void deleteTempZipFile(String zipFilePath) {
		deleteTempFile(new File(zipFilePath));
	}

	private void deleteTempFile(File f) {
		if (f == null || !f.exists()) {
			return;
		} else if (!f.isDirectory()) {
			f.delete();
		} else {
			for (File file : f.listFiles()) {
				if (file.isFile())
					file.delete(); // åˆ é™¤æ‰€æœ‰æ–‡ä»¶
				else if (file.isDirectory())
					deleteTempFile(file); // é€’è§„çš„æ–¹å¼�åˆ é™¤æ–‡ä»¶å¤¹
			}
			f.delete();// åˆ é™¤ç›®å½•æœ¬èº«
		}
	}

	private String zip(File zipDir) throws Exception {
		List<File> fileList = new ArrayList<File>();
		getAllFiles(zipDir, fileList);
		String zipFile = writeZipFile(zipDir, fileList);
		String pdbFile = zipFile.substring(0, zipFile.lastIndexOf("."))
				+ ".pdb";
		EncryptDecrypt encrypter = new EncryptDecrypt();
		try {
			byte[] keyBytes = { 11, 23, 35, 57, 69, 71, 83, 95 };
			FileInputStream fis = new FileInputStream(zipFile);
			FileOutputStream fos = new FileOutputStream(pdbFile);
			encrypter.encrypt(keyBytes, fis, fos);
			if (fis != null) {
				fis.close();
			}
			if (fos != null) {
				fos.close();
			}
		} catch (Exception e) {
			throw e;
		} finally {
			//deleteTempZipFile(zipFile);
		}
		return pdbFile;
	}

	private void getAllFiles(File zipDir, List<File> fileList) {
		File[] files = zipDir.listFiles();
		for (File file : files) {
			fileList.add(file);
			if (file.isDirectory()) {
				getAllFiles(file, fileList);
			}
		}
	}

	private String writeZipFile(File zipDir, List<File> fileList)
			throws Exception {
		FileOutputStream fos = null;
		ZipOutputStream zos = null;
		try {
			String zipFileName = zipDir.getPath() + ".zip";
			fos = new FileOutputStream(zipFileName);
			zos = new ZipOutputStream(fos);
			for (File file : fileList) {
				if (!file.isDirectory()) { // we only zip files, not
					// directories
					addToZip(zipDir, file, zos);
				}
			}
			return zipFileName;
		} catch (Exception e) {
			throw e;
		} finally {
			if (zos != null) {
				zos.close();
			}
			if (fos != null) {
				fos.close();
			}
		}
	}

	public void addToZip(File zipDir, File file, ZipOutputStream zos)
			throws Exception {
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(file);
			// we want the zipEntry's path to be a relative path that is
			// relative
			// to the directory being zipped, so chop off the rest of the path
			String zipFilePath = file.getCanonicalPath().substring(
					zipDir.getCanonicalPath().length() + 1,
					file.getCanonicalPath().length());
			// System.out.println("Writing '" + zipFilePath + "' to zip file");
			ZipEntry zipEntry = new ZipEntry(zipFilePath);
			zos.putNextEntry(zipEntry);
			byte[] bytes = new byte[1024];
			int length;
			while ((length = fis.read(bytes)) >= 0) {
				zos.write(bytes, 0, length);
			}
		} finally {
			if (fis != null) {
				fis.close();
			}
		}
	}

	private File selectExportDirectory() {
		JFileChooser fileChooser = new JFileChooser();
		fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		fileChooser.setDialogTitle("请选择存放数据导出文件的目录");
		fileChooser.setAcceptAllFileFilterUsed(false);
		fileChooser.setApproveButtonToolTipText("将导出的数据文件保存在所选的目录下");
		fileChooser.setFileFilter(new FileFilter() {

			@Override
			public boolean accept(File file) {
				if (file.isDirectory()) {
					return true;
				}
				return false;
			}

			@Override
			public String getDescription() {
				return "目录";
			}

		});
		fileChooser.setApproveButtonText("保存");
		if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
			File path = createExportFile(fileChooser.getSelectedFile());
			return path;
		}
		return null;
	}

	private File createExportFile(File directoryPath) {
		File dataFile = null;
		try {
			if (!directoryPath.isDirectory()) {
				JOptionPane.showMessageDialog(null, "ä½ é€‰æ‹©çš„ç›®å½•ä¸�å­˜åœ¨ï¼Œæ•°æ�®å¯¼å‡ºå¤±è´¥", Tools
						.get().getValue("LABEL_PROMPT_TITLE"),
						JOptionPane.INFORMATION_MESSAGE);
			} else {
				SimpleDateFormat formatter = new SimpleDateFormat(
						"yyyyMMddHHmmss");
				String fileName = "D" + formatter.format(new Date());
				dataFile = new File(directoryPath.getPath() + "\\" + fileName);
				dataFile.mkdir();
				new File(dataFile.getPath() + "\\"
						+ Tools.get().getValue("EXPORTDATAFILENAME"))
						.createNewFile();
				new File(dataFile.getPath() + "\\"
						+ Tools.get().getValue("EXPORTPICSFILENAME")).mkdir();
			}
		} catch (Exception e) {
			JOptionPane.showMessageDialog(null, "åˆ›å»ºæ•°æ�®å¯¼å‡ºæ–‡ä»¶å¤±è´¥ï¼�", Tools.get()
					.getValue("LABEL_PROMPT_TITLE"),
					JOptionPane.INFORMATION_MESSAGE);
			e.printStackTrace();
		} finally {
			;
		}
		return dataFile;
	}
}
